package tech.konata.packetfix.mixins;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.vialoadingbase.ViaLoadingBase;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItemFrame;
import net.minecraft.util.*;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Unique;
import tech.konata.packetfix.PluginMain;
import tech.konata.packetfix.modules.PacketFix;

import java.util.List;

@Mixin(EntityRenderer.class)
public class MixinEntityRenderer {

    @Unique
    private final Minecraft via_phosphate_packet_fix$mc = Minecraft.getMinecraft();

    @Overwrite
    public void getMouseOver(float partialTicks) {
        Entity entity = this.via_phosphate_packet_fix$mc.getRenderViewEntity();

        if (entity != null && this.via_phosphate_packet_fix$mc.theWorld != null) {
            this.via_phosphate_packet_fix$mc.mcProfiler.startSection("pick");
            this.via_phosphate_packet_fix$mc.pointedEntity = null;
            double d0 = this.via_phosphate_packet_fix$mc.playerController.getBlockReachDistance();
            this.via_phosphate_packet_fix$mc.objectMouseOver = entity.rayTrace(d0, partialTicks);
            double d1 = d0;
            Vec3 vec3 = entity.getPositionEyes(partialTicks);
            boolean flag = false;
            int i = 3;

            if (this.via_phosphate_packet_fix$mc.playerController.extendedReach()) {
                d0 = 6.0D;
                d1 = 6.0D;
            } else if (d0 > 3.0D) {
                flag = true;
            }

            if (this.via_phosphate_packet_fix$mc.objectMouseOver != null) {
                d1 = this.via_phosphate_packet_fix$mc.objectMouseOver.hitVec.distanceTo(vec3);
            }

            Vec3 vec31 = entity.getLook(partialTicks);
            Vec3 vec32 = vec3.addVector(vec31.xCoord * d0, vec31.yCoord * d0, vec31.zCoord * d0);
            /**
             * Pointed entity
             */
            Entity pointedEntity = null;
            Vec3 vec33 = null;
            float f = 1.0F;
            List<Entity> list = this.via_phosphate_packet_fix$mc.theWorld.getEntitiesInAABBexcluding(entity, entity.getEntityBoundingBox().addCoord(vec31.xCoord * d0, vec31.yCoord * d0, vec31.zCoord * d0).expand(f, f, f), Predicates.and(EntitySelectors.NOT_SPECTATING, new Predicate<Entity>() {
                public boolean apply(Entity p_apply_1_) {
                    return p_apply_1_.canBeCollidedWith();
                }
            }));
            double d2 = d1;

            for (int j = 0; j < list.size(); ++j) {
                Entity entity1 = list.get(j);
                float f1 = entity1.getCollisionBorderSize();
                AxisAlignedBB axisalignedbb = entity1.getEntityBoundingBox().expand(f1, f1, f1);
                MovingObjectPosition movingobjectposition = axisalignedbb.calculateIntercept(vec3, vec32);

                if (axisalignedbb.isVecInside(vec3)) {
                    if (d2 >= 0.0D) {
                        pointedEntity = entity1;
                        vec33 = movingobjectposition == null ? vec3 : movingobjectposition.hitVec;
                        d2 = 0.0D;
                    }
                } else if (movingobjectposition != null) {
                    double d3 = vec3.distanceTo(movingobjectposition.hitVec);

                    if (d3 < d2 || d2 == 0.0D)
                    {
                        boolean flag1 = false;

                        if (!flag1 && entity1 == entity.ridingEntity)
                        {
                            if (d2 == 0.0D)
                            {
                                pointedEntity = entity1;
                                vec33 = movingobjectposition.hitVec;
                            }
                        }
                        else
                        {
                            pointedEntity = entity1;
                            vec33 = movingobjectposition.hitVec;
                            d2 = d3;
                        }
                    }
                }
            }



            double distance = 3.0D;
            if (ViaLoadingBase.getInstance().getTargetVersion().newerThanOrEqualTo(ProtocolVersion.v1_12_2) && PluginMain.packetFix.isEnabled()) {
                distance = 2.9D;
            }

            if (pointedEntity != null && flag && vec3.distanceTo(vec33) > distance)
            {
                pointedEntity = null;
                this.via_phosphate_packet_fix$mc.objectMouseOver = new MovingObjectPosition(MovingObjectPosition$MovingObjectType.MISS, vec33, (EnumFacing)null, new BlockPos(vec33));
            }

            if (pointedEntity != null && (d2 < d1 || this.via_phosphate_packet_fix$mc.objectMouseOver == null)) {
                this.via_phosphate_packet_fix$mc.objectMouseOver = new MovingObjectPosition(pointedEntity, vec33);

                if (pointedEntity instanceof EntityLivingBase || pointedEntity instanceof EntityItemFrame) {
                    this.via_phosphate_packet_fix$mc.pointedEntity = pointedEntity;
                }
            }

            this.via_phosphate_packet_fix$mc.mcProfiler.endSection();
        }
    }

}
